<template>
  <el-aside width="260px" class="conversation-container h-100%">
    <!-- 左顶部：对话 -->
    <div class="h-100%">
      <el-button style="width: 100px; font-size: 15px" class="w-1/1 btn-new-conversation" type="primary" @click="createChat">
        <Icon icon="ep:plus" class="mr-5px" />
        新建对话
      </el-button>
      <!-- 左顶部：搜索对话 -->
      <el-input
        v-model="searchName"
        size="large"
        class="mt-10px search-input"
        placeholder="搜索历史记录"
        @keyup="searchConversation"
      >
        <template #prefix>
          <Icon icon="ep:search" />
        </template>
      </el-input>

      <!-- 左中间：对话列表 -->
      <div class="conversation-list">
        <!-- 情况一：加载中 -->
        <el-empty v-if="loading" description="." :v-loading="loading" />
        <!-- 情况二：按照 group 分组，展示聊天会话 list 列表 -->
        <div v-for="conversationKey in Object.keys(conversationMap)" :key="conversationKey">
          <div class="conversation-item classify-title" v-if="conversationMap[conversationKey].length">
            <el-text class="mx-1" size="small" tag="b">{{ conversationKey }}</el-text>
          </div>
          <div
            class="conversation-item"
            v-for="conversation in conversationMap[conversationKey]"
            :key="conversation.id"
            @click="handleConversationClick(conversation.id)"
            @mouseover="hoverConversationId = conversation.id"
            @mouseout="hoverConversationId = null"
          >
            <div :class="conversation.id === activeConversationId ? 'conversation active' : 'conversation'">
              <div class="title-wrapper">
                <img class="avatar" :src="conversation.roleAvatar || roleAvatarDefaultImg" />
                <span class="title">{{ conversation.title }}</span>
              </div>
              <div class="button-wrapper" v-show="hoverConversationId === conversation.id">
                <el-button class="btn" link @click.stop="handleTop(conversation)">
                  <el-icon title="置顶" v-if="!conversation.pinned">
                    <Top />
                  </el-icon>
                  <el-icon title="置顶" v-if="conversation.pinned">
                    <Bottom />
                  </el-icon>
                </el-button>
                <el-button class="btn" link @click.stop="updateChatTitle(conversation)">
                  <el-icon title="编辑">
                    <Edit />
                  </el-icon>
                </el-button>
                <el-button class="btn" link @click.stop="deleteMyChat(conversation)">
                  <el-icon title="删除对话">
                    <Delete />
                  </el-icon>
                </el-button>
              </div>
            </div>
          </div>
        </div>
        <!-- 底部占位  -->
        <div class="h-160px w-100%"></div>
      </div>
    </div>

    <!-- 左底部：工具栏 -->
    <div class="tool-box">
      <div>
        <el-button type="primary" link :icon="User"> 角色仓库 </el-button>
      </div>
      <div>
        <el-button type="primary" link :icon="Delete" @click="handleClearConversation"> 清空未置顶对话 </el-button>
      </div>
    </div>

    <!-- 角色仓库抽屉 -->
    <el-drawer title="角色仓库" size="754px">
      <RoleRepository />
    </el-drawer>
  </el-aside>
</template>

<script lang="ts" setup>
import roleAvatarDefaultImg from "@/assets/ai/gpt.svg";
import { ref, defineEmits, onMounted } from "vue";
import { Chat, createChatMy, getChatMyList, updateChat, deleteChat, deleteChatMyByUnpinned } from "@/api/ai/chat";
import { useMessage } from "@/hooks/useMessage";
import { ElMessageBox } from "element-plus";
import { Delete, User } from "@element-plus/icons-vue";

const message = useMessage();

const searchName = ref<string>(""); // 对话搜索
const loading = ref<Boolean>(false);
const conversationMap = ref<any>({}); // 对话分组 (置顶、今天、三天前、一星期前、一个月前)
const hoverConversationId = ref<number | null>(null); // 悬浮上去的对话
const activeConversationId = ref<number | null>(null); // 选中的对话，默认为 null
const loadingTime = ref<any>(null); // 加载中定时器
const conversationList = ref<Chat.ResChat[]>([]); // 对话列表

// 定义组件 props
const props = defineProps({
  activeId: {
    type: Number || null,
    required: true
  }
});
/** 清空对话 */
const handleClearConversation = async () => {
  await message.confirm("确认后对话会全部清空，置顶的对话除外。");
  await deleteChatMyByUnpinned();
  message.success("操作成功");
  // 清空 对话 和 对话内容
  activeConversationId.value = null;
  // 获取 对话列表
  await getChatList();
  // 回调 方法
  emits("onConversationClear");
};
/** 对话置顶 */
const handleTop = async (chat: Chat.ReqChat) => {
  // 更新对话置顶
  chat.pinned = !chat.pinned;
  await updateChat(chat);
  // 刷新对话
  await getChatList();
};

const updateChatTitle = async (chat: Chat.ReqChat) => {
  // 1. 二次确认
  try {
    const { value } = await ElMessageBox.prompt("修改标题", {
      inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // 判断非空，且非空格
      inputErrorMessage: "标题不能为空",
      inputValue: chat.title
    });
    // 2. 发起修改
    await updateChat({
      id: chat.id,
      title: value
    } as Chat.ReqChat);
    message.success("重命名成功");
    // 3. 刷新列表
    await getChatList();
    // 4. 过滤当前切换的
    const filterConversationList = conversationList.value.filter(item => {
      return item.id === chat.id;
    });
    if (filterConversationList.length > 0) {
      // tip：避免切换对话
      if (activeConversationId.value === filterConversationList[0].id) {
        emits("onConversationClick", filterConversationList[0]);
      }
    }
  } catch (e) {}
};
const deleteMyChat = async (chat: Chat.ReqChat) => {
  try {
    // 删除的二次确认
    await message.delConfirm(`是否确认删除对话 - ${chat.title}?`);
    // 发起删除
    await deleteChat(chat.id);
    message.success("对话已删除");
    // 刷新列表
    await getChatList();
    // 回调
    emits("onConversationDelete", chat);
  } catch {}
};
const searchConversation = async () => {
  if (!searchName.value.trim().length) {
    conversationMap.value = await getChatGroupByCreateTime(conversationList.value);
  } else {
    // 过滤
    const filterValues = conversationList.value.filter(item => {
      return item.title.includes(searchName.value.trim());
    });
    conversationMap.value = await getChatGroupByCreateTime(filterValues);
  }
};

const handleConversationClick = (id: number) => {
  // 过滤出选中的对话
  const filterConversation = conversationList.value.filter(item => {
    return item.id === id;
  });
  emits("onConversationClick", filterConversation[0]);
  // 切换对话
  if (filterConversation[0]) {
    activeConversationId.value = id;
  }
};

// 定义钩子
const emits = defineEmits(["onConversationCreate", "onConversationClick", "onConversationDelete", "onConversationClear"]);
/** 新建对话 */
const createChat = async () => {
  // 1. 新建对话
  const myChatRes = await createChatMy({} as Chat.ReqChat);
  const chatId: number = myChatRes.data;
  // 获取对话内容
  await getChatList();
  // 3. 选中对话
  handleConversationClick(chatId);
  // 4. 回调
  emits("onConversationCreate");
};

/**
 * 获取对话列表
 */
const getChatList = async () => {
  // 加载中
  try {
    loadingTime.value = setTimeout(() => {
      loading.value = true;
    }, 50);
    // 1.1 获取 对话数据
    const res = await getChatMyList();
    conversationList.value = res.data;
    // 1.3 没有任何对话情况
    if (conversationList.value.length === 0) {
      activeConversationId.value = null;
      conversationMap.value = {};
      return;
    }
    // 2. 对话根据时间分组(置顶、今天、一天前、三天前、七天前、30 天前)
    conversationMap.value = await getChatGroupByCreateTime(conversationList.value);
  } finally {
    // 清理定时器
    if (loadingTime.value) {
      clearTimeout(loadingTime.value);
    }
    // 加载完成
    loading.value = false;
  }
};
type GroupMap = Record<string, Chat.ResChat[]>;
const getChatGroupByCreateTime = async (list: Chat.ResChat[]) => {
  // 排序、指定、时间分组(今天、一天前、三天前、七天前、30天前)
  // noinspection NonAsciiCharacters
  const groupMap: GroupMap = {
    置顶: [],
    今天: [],
    一天前: [],
    三天前: [],
    七天前: [],
    三十天前: []
  };
  const now: number = Date.now();
  const oneDay: number = 24 * 60 * 60 * 1000;
  const threeDays: number = 3 * oneDay;
  const sevenDays: number = 7 * oneDay;
  const thirtyDays: number = 30 * oneDay;
  for (const conversation of list) {
    // 置顶
    if (conversation.pinned) {
      groupMap["置顶"].push(conversation);
      continue;
    }
    // 计算时间差（单位：毫秒）

    const dateObj = new Date(conversation.createTime);
    const diff = now - dateObj.getTime();
    // 根据时间间隔判断
    if (diff < oneDay) {
      groupMap["今天"].push(conversation);
    } else if (diff < threeDays) {
      groupMap["一天前"].push(conversation);
    } else if (diff < sevenDays) {
      groupMap["三天前"].push(conversation);
    } else if (diff < thirtyDays) {
      groupMap["七天前"].push(conversation);
    } else {
      groupMap["三十天前"].push(conversation);
    }
  }
  return groupMap;
};
onMounted(async () => {
  await getChatList();
  if (props.activeId) {
    activeConversationId.value = props.activeId;
  } else {
    // 首次默认选中第一个
    if (conversationList.value.length) {
      activeConversationId.value = conversationList.value[0].id;
      // 回调 onConversationClick
      emits("onConversationClick", conversationList.value[0]);
    }
  }
});
// 定义 public 方法
defineExpose({ createChat });
</script>

<style scoped lang="scss">
.conversation-container {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 10px 10px 0;
  overflow: hidden;

  .btn-new-conversation {
    padding: 18px 0;
  }

  .search-input {
    margin-top: 20px;
  }

  .conversation-list {
    height: 100%;
    overflow: auto;

    .classify-title {
      padding-top: 10px;
    }

    .conversation-item {
      margin-top: 5px;
    }

    .conversation {
      display: flex;
      flex: 1;
      flex-direction: row;
      align-items: center;
      justify-content: space-between;
      padding: 0 5px;
      line-height: 30px;
      cursor: pointer;
      border-radius: 5px;

      &.active {
        background-color: var(--el-color-primary-light-1);

        .button {
          display: inline-block;
        }
      }

      .title-wrapper {
        display: flex;
        flex-direction: row;
        align-items: center;
      }

      .title {
        max-width: 220px;
        padding: 2px 10px;
        overflow: hidden;
        font-size: 14px;
        font-weight: 400;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .avatar {
        display: flex;
        flex-direction: row;
        justify-items: center;
        width: 25px;
        height: 25px;
        border-radius: 5px;
      }

      // 对话编辑、删除
      .button-wrapper {
        right: 2px;
        display: flex;
        flex-direction: row;
        justify-items: center;
        color: #606266;

        .btn {
          margin: 0;
          font-size: 20px;
        }
      }
    }
  }

  // 角色仓库、清空未设置对话
  .tool-box {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 20px;
    line-height: 35px;
    color: var(--el-text-color);
    box-shadow: 0 0 1px 1px var(--el-header-text-color);
    height: 32px;

    > div {
      display: flex;
      align-items: center;
      padding: 0;
      margin: 0;
      color: #606266;
      cursor: pointer;

      > span {
        margin-left: 5px;
      }
    }
  }
}
</style>
